package net.gazhi.delonix.grac.service;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import net.gazhi.delonix.core.service.AbstractService;
import net.gazhi.delonix.core.thread.ThreadContext;
import net.gazhi.delonix.grac.entity.act.Action;
import net.gazhi.delonix.grac.entity.act.MenuItem;
import net.gazhi.delonix.grac.thread.GracThreadContext;

import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.method.HandlerMethod;

/**
 * Action 鉴权业务逻辑类
 * 
 * @author Jeffrey Lin
 */
@Service
@Transactional(readOnly = true)
public class ActionAuthorizationService extends AbstractService {

	/**
	 * 获取已授权给当前用户的 Action
	 * 
	 * @param forceUpdateThreadContext
	 *            是否强制更新线程上下文
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public List<Action> listAuthorizedActions(boolean forceUpdateThreadContext) {
		List<Action> actions = GracThreadContext.getAuthorizedActions();
		if (actions == null || forceUpdateThreadContext) {
			long userId = ThreadContext.getLoginUser().getId();
			actions = userId <= 0 ? new ArrayList<Action>() : dao.createCriteria(Action.class, "a").createAlias("a.roles", "r").createAlias("r.users", "u").add(Restrictions.eq("r.isDisabled", false))
					.add(Restrictions.eq("u.id", userId)).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
			GracThreadContext.setAuthorizedActions(actions);
		}
		return actions;
	}

	/**
	 * 获取已授权给当前用户的 Action
	 * 
	 * @return
	 */
	public List<Action> listAuthorizedActions() {
		return this.listAuthorizedActions(false);
	}

	/**
	 * 判断是否有执行方法的权限
	 * 
	 * @param method
	 * @return
	 */
	public boolean isAuthorized(HandlerMethod hm) {
		Method method = hm.getMethod();
		long actionId = ActionService.generateActionId(method.getDeclaringClass().getName() + "." + method.getName());
		for (Action a : this.listAuthorizedActions()) {
			if (a.getId().longValue() == actionId) {
				return true;
			}
		}
		return false;
	}

	@SuppressWarnings("unchecked")
	public Set<MenuItem> listAuthorizedRootMenuItems(String menuUsage) {
		List<MenuItem> items = dao.createCriteria(MenuItem.class, "it").createAlias("it.action", "act").createAlias("act.roles", "r").createAlias("r.users", "u")
				.add(Restrictions.eq("r.isDisabled", false)).add(Restrictions.eq("u.id", ThreadContext.getLoginUser().getId())).add(Restrictions.eq("it.menuUsage", menuUsage))
				.addOrder(Order.asc("it.id")).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
		Set<MenuItem> roots = new LinkedHashSet<MenuItem>();
		for (MenuItem it : items) {
			MenuItem root = this.navToRootMenuItem(it);
			roots.add(root);
		}
		return roots;
	}

	/**
	 * 递归到父节点，并设置 grantChilds
	 * 
	 * @param menu
	 * @return
	 */
	private MenuItem navToRootMenuItem(MenuItem item) {
		if (item.getParent() == null) {
			return item;
		}
		item.getParent().getChildItems().add(item);
		return this.navToRootMenuItem(item.getParent());
	}

}
